from ..math.mathematic import isInteger as _isInteger
from .bitcarry import Xor as _Xor
from .DESTable import *
from ..ess import dolist as _dolist
from math import log as _log

UNHEX: dict = {
    '0': 0,
    '1': 1,
    '2': 2,
    '3': 3,
    '4': 4,
    '5': 5,
    '6': 6,
    '7': 7,
    '8': 8,
    '9': 9,
    'a': 10,
    'b': 11,
    'c': 12,
    'd': 13,
    'e': 14,
    'f': 15,
    'A': 10,
    'B': 11,
    'C': 12,
    'D': 13,
    'E': 14,
    'F': 15,
}


def Dehamming(l):
    """由汉明码求出错误的比特位置"""
    return _dolist(_Xor, [x for x, y in enumerate(l) if y])


def Unhamming(l):
    """从汉明码中取出数据"""
    return [l[i] for i in [3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]]


def Hamming(binstr):
    """把11位数据填入16位汉明码"""
    o = [0]
    point = 0
    for i in range(1, 16):
        if _isInteger(_log(i, 2)):
            o.append(0)
        else:
            o.append(binstr[point])
            point += 1
    for i in range(3):
        j = 2 ** i
        o[j] = _dolist(_Xor, [o[x] for x in range(3, 16) if j & x == j])
    o[0] = _dolist(_Xor, o)
    return o


def str2utf_8(s: str) -> str:
    """将字符串以UTF-8编码为二进制"""
    return ''.join(map(lambda i: f"{bin(i)[2:]:0>8}", bytearray(s, "utf-8")))


def deutf_8(binary: str, leng: int) -> str:
    """将UTF-8解码为字符"""
    if binary:
        o, i = binary[leng + 1 : 8], 0
        while leng > i + 1:
            i += 1
            o += binary[(i << 3) + 2 : (i << 3) + 8]
        return chr(int(o, 2))
    else:
        return ''


def utf_82str(binary: str) -> str:
    """将UTF-8二进制字符串解码为字符串"""
    i, string = 0, []
    while i + 1 < len(binary):
        chartype = binary[i:].index('0')
        leng = chartype << 3 if chartype else 8
        string.append(deutf_8(binary[i : i + leng], chartype))
        i += leng
    return ''.join(string)


def CirShift(key: list, p: int) -> list:
    """循环左移p位"""
    return key[p:] + key[:p]


def getbit(num: int, pos: int) -> int:
    """获取num第pos位（从零算起）的比特"""
    return (num >> pos) % 2


def byte2bit(byt) -> list:
    return [getbit(byt[i // 8], 7 - i % 8) for i in range(len(byt) * 8)]


def IPreplace(word: list, table: list) -> list:
    """单表替换"""
    return [word[i - 1] for i in table]


def DESKey(key: list) -> list:
    """获取DES加密用密钥"""
    keylist = []
    key2 = byte2bit(key)
    temp = IPreplace(key2, DESReplaceKeyTable)
    D, C = temp[:28], temp[28:]
    for i in range(16):
        D, C = CirShift(D, DEShiftKey[i]), CirShift(C, DEShiftKey[i])
        keylist.append(IPreplace(D + C, DESqueezeKeyTable))
    return keylist


def DES(word: list, key, mode: int = 1) -> list:
    """DES加密算法"""
    temp = IPreplace(word, DESIPreplaceTable)
    L, R = temp[:32], temp[32:]
    keys = DESKey(key)[::mode]
    for i in range(16):
        R1 = IPreplace(R, DESpreadETable)
        sBox, sout = [R1[j] ^ keys[i][j] for j in range(48)], []
        for j in range(8):
            j1 = j * 6
            x = (sBox[j1] << 1) + sBox[j1 + 5]
            y = sum(sBox[j1 + 4 - k] << k for k in range(4))
            sout += [int(k) for k in f"{DESBoxS[j][x][y]:0>4b}"]
        P = IPreplace(sout, DESBoxPTable)
        L, R = R, [L[j] ^ P[j] for j in range(32)]
    return IPreplace(R + L, DESIPreplaceTable_1)
